//***************************************************************************//
//*
//* 内容摘要：QOS-FEC-NACK内部传输模式对外接口
//*	
//* 当前版本：V1.0		
//* 作    者：zhfayuan
//* 完成日期：2016-8-21
//**************************************************************************//

#if !defined(SDAVCOMMN_H)
#define SDAVCOMMN_H
#include "SDCommon.h"
#include "SDRTPComm.h"
#include "SDMessage.h"

enum FEC_REDUN_METHOD_TYPE
{
	//自动冗余度
	AUTO_REDUN = 0,
	//固定冗余度
	FIX_REDUN
};

//存放用户观测周期内网络状态情况可用于外层码率自适应等决策
//网络状态每个心跳周期计算一次，目前分为5种情况：
//空闲、轻载、满载、超载、拥塞
typedef struct NetWorkStatusCount
{
	//当前的统计次数（每心跳周期统计一次）
	UINT unTotalCount;
	//空闲
	UINT unFreeCount;
	//轻载
	UINT unLowCount;
	//满载
	UINT unFullCount;
	//超载
	UINT unOverCount;
	//拥塞
	UINT unBlockCount;
}NetWorkStatusCount;

//接收数据回调输出函数
typedef void (*ReciveDataCallBackFunc)(int len, BYTE *data, void *pObject);

//NACK机制下，本地发出的RTP包将缓存以备远端请求重发时所需
//本宏用于指定最大缓存的包数
#define NACK_LOCAL_SAVE_DEPTH	900


//每心跳包周期采样一个当前时刻丢包率和RTT数据，一定时间内的样本数据
//进行加权平均得到过滤后的丢包率和RTT，本宏定义滤波器抽头数。滤波处理
//有助于消除毛刺。
#define LOST_RATIO_AND_RTT_FILTER_SAMPLES	5

class CSDAudioReciveProcess;
class CSDVideoReciveProcess;
class CSDNeedRemoteRetransRequest;
class CSDAVCommn
{
public:
	CSDAVCommn();
	virtual ~CSDAVCommn();

public:
	// 服务器类型
	BOOL Create(char *strLocalIP, USHORT shLocalPort, char *strRemoteIP, UINT unQosDropDelay, 
				FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio, UINT unFecGroupSize = DEFAULT_GROUP_SIZE,
				ReciveDataCallBackFunc pfVideoRecCallBack = NULL, ReciveDataCallBackFunc pfAudioRecCallBack = NULL, 
				void *pObject = NULL, const char* strName = NULL);
#if ENABLE_UDP_PROXY_MODE
	// 客户端类型
	BOOL Create(char *strLocalIP, USHORT shLocalPort, char *strRemoteIP, USHORT shRemotePort, USHORT shRemoteRealPort, UINT unQosDropDelay, 
				FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio, UINT unFecGroupSize = DEFAULT_GROUP_SIZE,
				ReciveDataCallBackFunc pfVideoRecCallBack = NULL, ReciveDataCallBackFunc pfAudioRecCallBack = NULL,
				void *pObject = NULL, const char* strName = NULL);
#else
	// 客户端类型
	BOOL Create(char *strLocalIP, USHORT shLocalPort, char *strRemoteIP, USHORT shRemotePort, UINT unQosDropDelay, 
				FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio, UINT unFecGroupSize = DEFAULT_GROUP_SIZE,
				ReciveDataCallBackFunc pfVideoRecCallBack = NULL, ReciveDataCallBackFunc pfAudioRecCallBack = NULL,
				void *pObject = NULL, const char* strName = NULL);
#endif
	void Close();

	BOOL SendAudioData(int nLen, BYTE *byBuf);
	BOOL SendVideoData(int nLen, BYTE *byBuf, UINT unNaluNum = 0, UINT unNaluIndex = 0);

	//强制发送丢包，用于模拟测试
	BOOL ForceSendLost(LOST_METHOD_TYPE eLostMethod, UINT unLostValue, UINT unPacketsLostContinue = 1);

	//强制关闭或者开启发送端FEC，默认开启
	void FecEncode_Enable(bool bEnable);

	//关闭或开启视频通道NACK，默认关闭
	void QosNackForVideo_Enable(bool bEnable);

	//关闭或开启音频通道NACK，默认关闭
	void QosNackForAudio_Enable(bool bEnable);
public:
	virtual void OnReciveAudioData(int nLen, BYTE *byBuf){}
	virtual void OnReciveVideoData(int nLen, BYTE *byBuf){}
	virtual void OnReciveAudioError(){}
	virtual void OnReciveVideoError(){}

	//获得当前时刻下行的视频通道丢包率
	UINT GetCurrDownLostRatio(void) { return (UINT)(m_objVideoPros.MDrtpGetDownLostRatio() * 100); }

	//获得当前时刻下行音频通道丢包率
	UINT GetCurrDownLostRatioInAudio(void) { return (UINT)(m_objAudioPros.MDrtpGetDownLostRatio() * 100); }

	//获得当前下行的码率kbps,以视频通道作为统计标准
	float GetCurrDownBitrate(void) { return m_objVideoPros.MDrtpGetDownBitrate(); }

	//获得当前下行的码率kbps，以音频通道作为统计标准
	float GetCurrDownBitrateInAudio(void) { return m_objAudioPros.MDrtpGetDownBitrate(); }

	//获得当前上行的码率kbps,以视频通道作为统计标准
	float GetCurrUpBitrate(void) { return m_objVideoPros.MDrtpGetUpBitrate(); }

	//获得当前上行的码率kbps，以音频通道作为统计标准
	float GetCurrUpBitrateInAudio(void) { return m_objAudioPros.MDrtpGetUpBitrate(); }

	//获得当前时刻上行的视频通道丢包率
	UINT GetCurrUpLostRatio(void) { return m_objVideoPros.GetUpLostRatio(); }

	//获得经过了加权滤波后当前上行丢包率
	float GetFilterUpLostRatio(void) { return m_fLostRateFiltered; }

	//获得当前时刻上行的音频通道丢包率
	UINT GetCurrUpLostRatioInAudio(void) { return m_objAudioPros.GetUpLostRatio(); }

	//获得当前时刻视频通道上的RTT
	UINT GetCurrDelayInMs(void);

	//获得经过了加权滤波后当前RTT
	float GetFilterDelayInMs(void) {return m_fRttFiltered; }

	//获得内部评估的网络状态统计数据
	void GetNetWorkStatusCount(NetWorkStatusCount *ptNetWorkStatusCount);
	//复位网络状态统计值，开始新的统计
	void ClearNetWorkStatusCount();

	//获得远端当前FEC配置参数
	BOOL GetFecParamsForRemoteVideo(UINT8 &byMediaPacketNum, UINT8 &byRedunPacketNum)
	{
		return m_objVideoPros.GetTranParamsForRemoteFec(byMediaPacketNum, byRedunPacketNum);
	}

	BOOL GetFecParamsForRemoteAudio(UINT8 &byMediaPacketNum, UINT8 &byRedunPacketNum)
	{
		return m_objAudioPros.GetTranParamsForRemoteFec(byMediaPacketNum, byRedunPacketNum);
	}

	//音视频通道是否都已收到握手包
	BOOL HaveRecvHandMsgOnAVChannel(void) 
	{
		if ((m_objVideoPros.HaveRecvHandMsg() == TRUE) && (m_objAudioPros.HaveRecvHandMsg() == TRUE))
		{
			return TRUE;
		}
		else
		{
			return FALSE;
		}
	}

	//获得远端IP和端口（从收到远端的包中提取得到，为NAT后IP和端口）
	void GetRemoteNatIpAndPortForAv(UINT &unVideoChannelIp, USHORT &usVideoChannelPort, UINT &unAudioChannelIp, USHORT &usAudioChannelPort)
	{
		m_objVideoPros.GetRemoteNatIpAndPort(unVideoChannelIp, usVideoChannelPort);
		m_objAudioPros.GetRemoteNatIpAndPort(unAudioChannelIp, usAudioChannelPort);
	}

#if ENABLE_NACK	
	//远端在视频通道上是否使能的NACK
	BOOL RemoteNackForVideoIsEnable(void);
#endif

	//指定音视频接收缓存队列深度，一般情况下无需调用设置使用默认值即可，特殊情况可以调整
	//一般传输带宽越高，队列应该设置越深，防止队列溢出。已知传输带宽较低的场合可以使用默认值
	//以节省内存开销。请于Create接口前调用
	void SetQosBuffManDepth(int nDepth);

	//指定底层socket接收和发送buff大小(SO_SNDBUF and SO_RCVBUF)，一般情况下使用默认值即可
	//特殊情况下可以根据实际情况调整，请于Create接口前调用
	void SetUdpSocketBuffSize(int nBuffSize);

	//底层Socket工作在阻塞模式还是非阻塞模式，默认为阻塞模式
	void SetUdpSocketInBlockMode(BOOL bSocketInBlockMode);

	//设置定时心跳包的发送频率
	void SetHandlePacketIntervalMs(int nHandleIntervalMs) { m_nHandleIntervalMs = nHandleIntervalMs;}

#if ENABLE_NACK
	//设置处理远端IDR请求的回调函数，若不设置则默认不响应IDR请求
	void SetRemoteIdrReqProcesser(CallBack_OnReciveIdrReq pfIdrReqProcess, void* pIdrReqObject);
#endif

#if ENABLE_DYNAMIC_GROUP_SIZE
	//关闭或开启视频通道动态Group功能，默认关闭
	void DynamicGroupSizeForVideo_Enable(bool bEnable);	
#endif

private:
	CSDThread               m_thdCreateHandle;

	CSDRTPSliceCommn        m_objAudioPros;
	int						m_nAudioQosBufSize;

	CSDRTPSliceCommn        m_objVideoPros;
	CSDRTPSliceCommn        m_objVideoNackPros;
	BOOL					m_bCreateVideoNackChannel;
	int						m_nVideoQosBufSize;
	CSDAudioReciveProcess*  m_objAudioRecive;

	CSDVideoReciveProcess*  m_objVideoRecive;
	CSDVideoReciveProcess*  m_objVideoNackRecive;
	CSDNeedRemoteRetransRequest* m_objVideoNeedRemoteRetrans;

	mysockaddr              m_tLocalAddr;
	mysockaddr              m_tRemoteAddr;

	void*                   m_pvAudioSend;
	void*                   m_pvVideoSend;
	void*                   m_pvAudioRecv;
	void*                   m_pvVideoRecv;
	void*                   m_pvAudioOutput;
	void*                   m_pvVideoOutput;
	void*					m_pvHandle;//锁握手包,close时要等握手线程退出以后在关闭
	CSDEvent                m_evtHandle;
	int						m_nHandleIntervalMs;
	bool					m_bAvComClosed;
	ReciveDataCallBackFunc  m_pfRecvAudioDataCallBack;
	ReciveDataCallBackFunc  m_pfRecvVideoDataCallBack;
	void*					m_pCallBackParam;
	//是否响应远端NACK
	BOOL					m_bEnableVideoRemoteNackReq;
	//存放当前时刻前一段时间的丢包率和RTT数据
	UINT					m_aunLostRatioCache[LOST_RATIO_AND_RTT_FILTER_SAMPLES];
	UINT					m_aunRttCache[LOST_RATIO_AND_RTT_FILTER_SAMPLES];
	UINT					m_unCacheIndex;
	//用于丢包率和RTT滤波的滤波器系数
	float					m_afFilterCoeff[LOST_RATIO_AND_RTT_FILTER_SAMPLES];
	//当前时刻滤波处理后的实时丢包率和RTT
	float					m_fLostRateFiltered;
	float					m_fRttFiltered;
	//网络状况计数
	NetWorkStatusCount		m_tNetWorkStatusCount;
	//网络状态获取和清除使用的锁保护
	void*                   m_pvCsNetWork;
	//记录发送视频数据的数目
	UINT					m_unVideoSendCount;
	//NACK请求Unique ID的起始随机值(音视频NACK复用)
	UINT					m_unUniqueNackReqId;
	//记录上一次IDR请求的时间以便控制IDR请求的频率
	long					m_nPrevIdrReqTime;

private:
	static   int ThreadHandleProc(void* pParam);
	static   int ThreadClose(void* pParam);
	BOOL mfCreate(FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio, UINT unFecGroupSize, const char* strName);
	int mfHandle();
	void mfUpdateNetworkStatus(BOOL bDataIsSending);
	float mfGetLostPacketScore(float fLostPacketRatio);
	float mfGetRttScore(float fRtt);

	static int ThreadReciveAudio(int nLen, char* pBuf, void *pObject);
	static int ThreadReciveVideo(int nLen, char* pBuf, void *pObject);
	CSDThreadProcessData2* m_pReciveAudioThd;
	CSDThreadProcessData2* m_pReciveVideoThd;

private:
	static void CallReciveAudioData(CSDAVCommn* pCommn, int nLen, BYTE *byBuf);
	static void CallReciveVideoData(CSDAVCommn* pCommn, int nLen, BYTE *byBuf);

#if ENABLE_NACK	
	static void CallReciveVideoNackReqFromRemote(CSDAVCommn* pCommn, int nLen, BYTE *byBuf);

	static void CallNeedRemoteRetransVideo(CSDAVCommn* pCommn, unsigned short usStartSeq, unsigned short usEndSeq);

	static UINT CallGetRttOnVideoNackChannel(CSDAVCommn* pCommn);

	static BOOL CallGetRemoteNackStatusVideo(CSDAVCommn* pCommn);

	//本地请求远端编码发送IDR帧
	static void CallSendIdrReqToRemote(void* pObject);
#endif

	static void CallReciveAudioError(CSDAVCommn* pCommn);
	static void CallReciveVideoError(CSDAVCommn* pCommn);
};

#endif // !defined(SDAVCOMMN_H)
